{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sgJos9SJNkht"
      },
      "source": [
        "# Llama 3 hosted on Groq + function calling + E2B Code interpreter        \n",
        "**Powered by open-source [Code Interpreter SDK](https://github.com/e2b-dev/code-interpreter) by [E2B](https://e2b.dev/docs)**\n",
        "\n",
        "E2B's code interpreter SDK quickly creates a secure cloud sandbox powered by [Firecracker](https://github.com/firecracker-microvm/firecracker).\n",
        "\n",
        "Inside this sandbox is a running Jupyter server that the LLM can use."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c3XPiIUY1vqt"
      },
      "source": [
        "### Step 1: Install dependencies\n",
        "\n",
        "We start by install the [E2B code interpreter SDK](https://github.com/e2b-dev/code-interpreter) and [Groq's Python SDK](https://console.groq.com/)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "OLxqUGV5_wnv",
        "outputId": "7725a7dd-4b45-4913-c974-e57e471c687f"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Collecting groq\n",
            "  Downloading groq-0.5.0-py3-none-any.whl (75 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.0/75.0 kB\u001b[0m \u001b[31m937.3 kB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hCollecting e2b_code_interpreter\n",
            "  Downloading e2b_code_interpreter-0.0.3-py3-none-any.whl (10.0 kB)\n",
            "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.10/dist-packages (from groq) (3.7.1)\n",
            "Requirement already satisfied: distro<2,>=1.7.0 in /usr/lib/python3/dist-packages (from groq) (1.7.0)\n",
            "Collecting httpx<1,>=0.23.0 (from groq)\n",
            "  Downloading httpx-0.27.0-py3-none-any.whl (75 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.6/75.6 kB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hRequirement already satisfied: pydantic<3,>=1.9.0 in /usr/local/lib/python3.10/dist-packages (from groq) (2.7.0)\n",
            "Requirement already satisfied: sniffio in /usr/local/lib/python3.10/dist-packages (from groq) (1.3.1)\n",
            "Requirement already satisfied: typing-extensions<5,>=4.7 in /usr/local/lib/python3.10/dist-packages (from groq) (4.11.0)\n",
            "Collecting e2b>=0.14.11 (from e2b_code_interpreter)\n",
            "  Downloading e2b-0.14.14-py3-none-any.whl (100 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m100.3/100.3 kB\u001b[0m \u001b[31m4.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hRequirement already satisfied: websocket-client<2.0.0,>=1.7.0 in /usr/local/lib/python3.10/dist-packages (from e2b_code_interpreter) (1.7.0)\n",
            "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->groq) (3.7)\n",
            "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->groq) (1.2.1)\n",
            "Collecting aenum>=3.1.11 (from e2b>=0.14.11->e2b_code_interpreter)\n",
            "  Downloading aenum-3.1.15-py3-none-any.whl (137 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m137.6/137.6 kB\u001b[0m \u001b[31m2.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hRequirement already satisfied: aiohttp>=3.8.4 in /usr/local/lib/python3.10/dist-packages (from e2b>=0.14.11->e2b_code_interpreter) (3.9.5)\n",
            "Collecting jsonrpcclient>=4.0.3 (from e2b>=0.14.11->e2b_code_interpreter)\n",
            "  Downloading jsonrpcclient-4.0.3-py3-none-any.whl (7.0 kB)\n",
            "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from e2b>=0.14.11->e2b_code_interpreter) (2.8.2)\n",
            "Requirement already satisfied: requests>=2.31.0 in /usr/local/lib/python3.10/dist-packages (from e2b>=0.14.11->e2b_code_interpreter) (2.31.0)\n",
            "Requirement already satisfied: urllib3>=1.25.3 in /usr/local/lib/python3.10/dist-packages (from e2b>=0.14.11->e2b_code_interpreter) (2.0.7)\n",
            "Collecting websockets>=11.0.3 (from e2b>=0.14.11->e2b_code_interpreter)\n",
            "  Downloading websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (130 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m130.2/130.2 kB\u001b[0m \u001b[31m4.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hRequirement already satisfied: certifi in /usr/local/lib/python3.10/dist-packages (from httpx<1,>=0.23.0->groq) (2024.2.2)\n",
            "Collecting httpcore==1.* (from httpx<1,>=0.23.0->groq)\n",
            "  Downloading httpcore-1.0.5-py3-none-any.whl (77 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m77.9/77.9 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hCollecting h11<0.15,>=0.13 (from httpcore==1.*->httpx<1,>=0.23.0->groq)\n",
            "  Downloading h11-0.14.0-py3-none-any.whl (58 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m3.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hRequirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1.9.0->groq) (0.6.0)\n",
            "Requirement already satisfied: pydantic-core==2.18.1 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1.9.0->groq) (2.18.1)\n",
            "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp>=3.8.4->e2b>=0.14.11->e2b_code_interpreter) (1.3.1)\n",
            "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp>=3.8.4->e2b>=0.14.11->e2b_code_interpreter) (23.2.0)\n",
            "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp>=3.8.4->e2b>=0.14.11->e2b_code_interpreter) (1.4.1)\n",
            "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp>=3.8.4->e2b>=0.14.11->e2b_code_interpreter) (6.0.5)\n",
            "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp>=3.8.4->e2b>=0.14.11->e2b_code_interpreter) (1.9.4)\n",
            "Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp>=3.8.4->e2b>=0.14.11->e2b_code_interpreter) (4.0.3)\n",
            "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.8.2->e2b>=0.14.11->e2b_code_interpreter) (1.16.0)\n",
            "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.31.0->e2b>=0.14.11->e2b_code_interpreter) (3.3.2)\n",
            "Installing collected packages: aenum, websockets, jsonrpcclient, h11, httpcore, httpx, e2b, groq, e2b_code_interpreter\n",
            "Successfully installed aenum-3.1.15 e2b-0.14.14 e2b_code_interpreter-0.0.3 groq-0.5.0 h11-0.14.0 httpcore-1.0.5 httpx-0.27.0 jsonrpcclient-4.0.3 websockets-12.0\n"
          ]
        }
      ],
      "source": [
        "%pip install groq e2b_code_interpreter==1.0.0"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MJDyfcPYyLe7"
      },
      "source": [
        "### Step 2: Define API keys, prompt, and tools\n",
        "\n",
        "Let's define our variables with API keys for Groq and E2B together with the model ID, prompt, and our tools."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "id": "NYAAAS_kFD87"
      },
      "outputs": [],
      "source": [
        "# TODO: Get your Groq AI API key from https://console.groq.com/\n",
        "GROQ_API_KEY = \"\"\n",
        "\n",
        "# TODO: Get your E2B API key from https://e2b.dev/docs\n",
        "E2B_API_KEY = \"\"\n",
        "\n",
        "# Or use 8b version\n",
        "# MODEL_NAME = \"llama3-8b-8192\"\n",
        "MODEL_NAME = \"llama3-70b-8192\"\n",
        "\n",
        "SYSTEM_PROMPT = \"\"\"you are a python data scientist. you are given tasks to complete and you run python code to solve them.\n",
        "- the python code runs in jupyter notebook.\n",
        "- every time you call `execute_python` tool, the python code is executed in a separate cell. it's okay to multiple calls to `execute_python`.\n",
        "- display visualizations using matplotlib or any other visualization library directly in the notebook. don't worry about saving the visualizations to a file.\n",
        "- you have access to the internet and can make api requests.\n",
        "- you also have access to the filesystem and can read/write files.\n",
        "- you can install any pip package (if it exists) if you need to but the usual packages for data analysis are already preinstalled.\n",
        "- you can run any python code you want, everything is running in a secure sandbox environment\"\"\"\n",
        "\n",
        "\n",
        "tools = [\n",
        "  {\n",
        "    \"type\": \"function\",\n",
        "      \"function\": {\n",
        "        \"name\": \"execute_python\",\n",
        "        \"description\": \"Execute python code in a Jupyter notebook cell and returns any result, stdout, stderr, display_data, and error.\",\n",
        "        \"parameters\": {\n",
        "          \"type\": \"object\",\n",
        "          \"properties\": {\n",
        "            \"code\": {\n",
        "              \"type\": \"string\",\n",
        "              \"description\": \"The python code to execute in a single cell.\",\n",
        "            }\n",
        "          },\n",
        "          \"required\": [\"code\"],\n",
        "        },\n",
        "      },\n",
        "  }\n",
        "]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "10O-rSQcy4Bi"
      },
      "source": [
        "### Step 3: Implement the method for code interpreting\n",
        "\n",
        "Here's the main function that use the E2B code interpreter SDK. We'll be calling this function a little bit further when we're parsing the Llama's response with tool calls."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "BpiwOkTqEeBh"
      },
      "outputs": [],
      "source": [
        "def code_interpret(e2b_code_interpreter, code):\n",
        "  print(\"Running code interpreter...\")\n",
        "  exec = e2b_code_interpreter.run_code(code,\n",
        "  on_stderr=lambda stderr: print(\"[Code Interpreter]\", stderr),\n",
        "  on_stdout=lambda stdout: print(\"[Code Interpreter]\", stdout))\n",
        "\n",
        "  if exec.error:\n",
        "    print(\"[Code Interpreter ERROR]\", exec.error)\n",
        "  else:\n",
        "    return exec.results"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A1eYw4jKz3RX"
      },
      "source": [
        "### Step 4: Implement the method for calling LLM and parsing tools\n",
        "\n",
        "Now we're going to define and implement `chat_with_llama` method. In this method, we'll call the LLM with our `tools` dictionary, parse the output, and call our `code_interpret` method we defined above."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {
        "id": "IsLjFlRW_TAR"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import json\n",
        "import re\n",
        "from groq import Groq\n",
        "\n",
        "client = Groq(api_key=GROQ_API_KEY)\n",
        "\n",
        "def chat_with_llama(e2b_code_interpreter, user_message):\n",
        "  print(f\"\\n{'='*50}\\nUser message: {user_message}\\n{'='*50}\")\n",
        "\n",
        "  messages = [\n",
        "      {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
        "      {\"role\": \"user\", \"content\": user_message}\n",
        "  ]\n",
        "\n",
        "  response = client.chat.completions.create(\n",
        "      model=MODEL_NAME,\n",
        "      messages=messages,\n",
        "      tools=tools,\n",
        "      tool_choice=\"auto\",\n",
        "      max_tokens=4096,\n",
        "  )\n",
        "\n",
        "  response_message = response.choices[0].message\n",
        "  tool_calls = response_message.tool_calls\n",
        "\n",
        "  if tool_calls:\n",
        "    for tool_call in tool_calls:\n",
        "      function_name = tool_call.function.name\n",
        "      function_args = json.loads(tool_call.function.arguments)\n",
        "      if function_name == \"execute_python\":\n",
        "        code = function_args[\"code\"]\n",
        "        code_interpreter_results = code_interpret(e2b_code_interpreter, code)\n",
        "        return code_interpreter_results\n",
        "      else:\n",
        "        raise Exception(f\"Unknown tool {function_name}\")\n",
        "  else:\n",
        "    print(f\"(No tool call in model's response) {response_message}\")\n",
        "    return []\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1ybhpXok1tQC"
      },
      "source": [
        "### Step 5: Put everything together\n",
        "In this last step, we put all the pieces together. We intantiate a new code interpreter instance using\n",
        "```python\n",
        "with CodeInterpreter(api_key=E2B_API_KEY) as code_interpreter:\n",
        "```\n",
        "\n",
        "and then call the `chat_with_llama` method with our user message and the `code_interpreter` instance."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 561
        },
        "id": "wKSWobclENIq",
        "outputId": "1fb962a3-b33d-4d53-edb8-35a6355744d8"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "==================================================\n",
            "User message: Visualize a distribution of height of men based on the latest data you know\n",
            "==================================================\n",
            "Running code interpreter...\n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkcAAAHHCAYAAAC1G/yyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABHHUlEQVR4nO3deXhTZf7//1cK3QJtoXSjgoVBZBEQBcQqikqHVYbN7wDCsEwVR+kI4jKigA4oKCoiiCJ+lEXBBUVkEBjKroCICIKALKKA0qZUIG0JbdP2/P7w18wJLdCEdKPPx3Xlush97vuc97kbyouT+yQWwzAMAQAAQJLkV94FAAAAVCSEIwAAABPCEQAAgAnhCAAAwIRwBAAAYEI4AgAAMCEcAQAAmBCOAAAATAhHAAAAJoQjwIeeffZZWSyWMjnWHXfcoTvuuMP1fMOGDbJYLPrkk0/K5PjDhg1TgwYNyuRY3srKytJ9992nmJgYWSwWjR49usxr+OWXX2SxWDRv3jyvx7788su+L8yH8vLy9MQTT6h+/fry8/NT7969y7sk4LIQjoALmDdvniwWi+sRFBSk2NhYdenSRTNmzFBmZqZPjnPixAk9++yz2rVrl0/250sVubaSmDx5subNm6cHH3xQ7733nv72t79dsG+DBg109913F7utrIOnN1asWKFnn322XI797rvv6qWXXtI999yj+fPn65FHHrlg3zvuuEMWi0WNGzcudntycrLr71xFnm9c2aqXdwFARTdx4kQ1bNhQTqdTqamp2rBhg0aPHq1p06Zp2bJlatWqlavvuHHj9OSTT3q0/xMnTujf//63GjRooNatW5d43OrVqz06jjcuVtvbb7+tgoKCUq/hcqxbt04333yznnnmmXKrIS4uTufOnZO/v3+pHmfFihWaNWtWuQSkdevW6aqrrtKrr75aov5BQUE6fPiwvvnmG910001u2xYuXKigoCBlZ2eXRqlAiXDlCLiEbt26afDgwRo+fLjGjh2r//73v1qzZo3S0tL0l7/8RefOnXP1rV69uoKCgkq1HofDIUkKCAhQQEBAqR7rYvz9/RUYGFhuxy+JtLQ01apVq1xrKLzqWK1atXKtozR5Os+NGjVSkyZN9MEHH7i1Z2dn67PPPlOPHj18XCHgGcIR4IW77rpL48eP19GjR/X++++72otbc5ScnKwOHTqoVq1aqlmzppo0aaKnnnpK0h9v17Rr106SNHz4cNfbCYXrU+644w61aNFCO3bs0O233y6r1eoae/6ao0L5+fl66qmnFBMToxo1augvf/mLjh8/7tanQYMGGjZsWJGx5n1eqrbi1hydPXtWjz76qOrXr6/AwEA1adJEL7/8sgzDcOtnsViUlJSkpUuXqkWLFgoMDNR1112nVatWFT/h50lLS1NiYqKio6MVFBSk66+/XvPnz3dtL3wb7Oeff9YXX3zhqv2XX34p0f5L6rffftPf//53RUdHu87h3XffdetzoTVHixcvVvPmzRUUFKQWLVros88+u+g6rjlz5qhRo0YKDAxUu3bttH37dte2YcOGadasWZLk9lZwoQ8//FBt2rRRSEiIQkND1bJlS7322muXPL9L/TwLz239+vXau3ev67gbNmy45L4HDhyojz76yO3q43/+8x85HA799a9/LXZMSea78Gf/8ccf6/nnn1e9evUUFBSkTp066fDhw5esC5B4Ww3w2t/+9jc99dRTWr16te6///5i++zdu1d33323WrVqpYkTJyowMFCHDx/W5s2bJUnNmjXTxIkTNWHCBI0YMUK33XabJOmWW25x7eP3339Xt27dNGDAAA0ePFjR0dEXrev555+XxWLRv/71L6WlpWn69OlKSEjQrl27FBwcXOLzK0ltZoZh6C9/+YvWr1+vxMREtW7dWv/973/1+OOP67fffivylstXX32lJUuW6KGHHlJISIhmzJihfv366dixY6pTp84F6zp37pzuuOMOHT58WElJSWrYsKEWL16sYcOG6cyZMxo1apSaNWum9957T4888ojq1aunRx99VJIUGRl50XN2Op1KT08v0m6324u02Ww23Xzzza6gFxkZqZUrVyoxMVEZGRkXXfz9xRdfqH///mrZsqWmTJmi06dPKzExUVdddVWx/RctWqTMzEw98MADslgsmjp1qvr27asjR47I399fDzzwgE6cOKHk5GS99957bmOTk5M1cOBAderUSS+++KIkaf/+/dq8ebNGjRp1wRpL8vOMjIzUe++9p+eff15ZWVmaMmWKpD9eO5dy77336tlnn9WGDRt01113uc6zU6dOioqKKtLf0/l+4YUX5Ofnp8cee0x2u11Tp07VoEGDtG3btkvWBsgAUKy5c+cakozt27dfsE9YWJhxww03uJ4/88wzhvmv1auvvmpIMk6ePHnBfWzfvt2QZMydO7fIto4dOxqSjNmzZxe7rWPHjq7n69evNyQZV111lZGRkeFq//jjjw1JxmuvveZqi4uLM4YOHXrJfV6stqFDhxpxcXGu50uXLjUkGc8995xbv3vuucewWCzG4cOHXW2SjICAALe277//3pBkzJw5s8ixzKZPn25IMt5//31XW25urhEfH2/UrFnT7dzj4uKMHj16XHR/5r6SLvpYvHixq39iYqJRt25dIz093W0/AwYMMMLCwgyHw2EYhmH8/PPPReawZcuWRr169YzMzExX24YNGwxJbnNaOLZOnTrGqVOnXO2ff/65Icn4z3/+42obOXKkUdyv9FGjRhmhoaFGXl5eieahkCc/z44dOxrXXXddifZr7tu2bVsjMTHRMAzDOH36tBEQEGDMnz/f9Vr2Zr4LxzZr1szIyclx9XvttdcMScaePXs8mAVUVbytBlyGmjVrXvSutcJ1GJ9//rnXi5cDAwM1fPjwEvcfMmSIQkJCXM/vuece1a1bVytWrPDq+CW1YsUKVatWTQ8//LBb+6OPPirDMLRy5Uq39oSEBDVq1Mj1vFWrVgoNDdWRI0cueZyYmBgNHDjQ1ebv76+HH35YWVlZ2rhxo9fn0L59eyUnJxd5nH8rvWEY+vTTT9WzZ08ZhqH09HTXo0uXLrLb7fruu++KPcaJEye0Z88eDRkyRDVr1nS1d+zYUS1btix2TP/+/VW7dm3X88KreJeaK+mP1+DZs2eVnJx8yb5mnv48vXHvvfdqyZIlys3N1SeffKJq1aqpT58+Rfp5M9/Dhw93W5PnyZwBvK0GXIasrKxi3wIo1L9/f/3f//2f7rvvPj355JPq1KmT+vbtq3vuuUd+fiX7v8lVV13l0cLr82+Rtlgsuuaaa3y+3uZ8R48eVWxsrFswk/73FsvRo0fd2q+++uoi+6hdu7ZOnz59yeM0bty4yPxd6DieiIiIUEJCQpH26tXdf1WePHlSZ86c0Zw5czRnzpxi95WWllZse2F911xzTZFt11xzTbGh6vy5KgxKl5orSXrooYf08ccfq1u3brrqqqvUuXNn/fWvf1XXrl0vOs7Tn6c3BgwYoMcee0wrV67UwoULdffddxc5nuTdfF/OnAGEI8BLv/76q+x2e7H/yBUKDg7Wpk2btH79en3xxRdatWqVPvroI911111avXp1ie5g8mSdUEld6IMq8/Pzy+yuqgsdxzhv8XZFVHgVcPDgwRo6dGixfcwf8XC5LmeuoqKitGvXLv33v//VypUrtXLlSs2dO1dDhgxxW8ReHurWras77rhDr7zyijZv3qxPP/202H7ezHdlfn2h/BGOAC8VLnzt0qXLRfv5+fmpU6dO6tSpk6ZNm6bJkyfr6aef1vr165WQkODzT9Q+dOiQ23PDMHT48GG3fzxq166tM2fOFBl79OhR/elPf3I996S2uLg4rVmzRpmZmW7/+//xxx9d230hLi5Ou3fvVkFBgdvVI18f52IiIyMVEhKi/Pz8Yq80XUxhfcXdOXU5d1Nd7GcVEBCgnj17qmfPniooKNBDDz2kt956S+PHj79guC+rn+e9996r++67T7Vq1VL37t2L7XM58w14gzVHgBfWrVunSZMmqWHDhho0aNAF+506dapIW+GHKebk5EiSatSoIUnFhhVvLFiwwG0d1CeffKKUlBR169bN1daoUSN9/fXXys3NdbUtX768yC3/ntTWvXt35efn6/XXX3drf/XVV2WxWNyOfzm6d++u1NRUffTRR662vLw8zZw5UzVr1lTHjh19cpyLqVatmvr166dPP/1UP/zwQ5HtJ0+evODY2NhYtWjRQgsWLFBWVparfePGjdqzZ4/XNV3oZ/X777+7Pffz83MF5cLXYHHK6ud5zz336JlnntEbb7xxwbePL2e+AW9w5Qi4hJUrV+rHH39UXl6ebDab1q1bp+TkZMXFxWnZsmUX/dDHiRMnatOmTerRo4fi4uKUlpamN954Q/Xq1VOHDh0k/RFUatWqpdmzZyskJEQ1atRQ+/bt1bBhQ6/qDQ8PV4cOHTR8+HDZbDZNnz5d11xzjdvHDdx333365JNP1LVrV/31r3/VTz/9pPfff99tgbSntfXs2VN33nmnnn76af3yyy+6/vrrtXr1an3++ecaPXp0kX17a8SIEXrrrbc0bNgw7dixQw0aNNAnn3yizZs3a/r06cWuWSkNL7zwgtavX6/27dvr/vvvV/PmzXXq1Cl99913WrNmTbHBuNDkyZPVq1cv3XrrrRo+fLhOnz6t119/XS1atHALTJ5o06aNJOnhhx9Wly5dVK1aNQ0YMED33XefTp06pbvuukv16tXT0aNHNXPmTLVu3fqit9yX1c8zLCys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qqXExERlZWX5tE4AAHBl8GrNUa1atdSnTx9f11LE6dOndeutt+rOO+/UypUrFRkZqUOHDql27dquPlOnTtWMGTM0f/58NWzYUOPHj1eXLl20b98+BQUFSZIGDRqklJQUJScny+l0avjw4RoxYoQWLVpU6ucAAAAqF6/C0dy5c31dR7FefPFF1a9f3+145i+8NQxD06dP17hx49SrVy9J0oIFCxQdHa2lS5dqwIAB2r9/v1atWqXt27erbdu2kqSZM2eqe/fuevnllxUbG1sm5wIAACoHr95Wk6S8vDytWbNGb731ljIzMyVJJ06c8OnbVcuWLVPbtm31//7f/1NUVJRuuOEGvf32267tP//8s1JTU5WQkOBqCwsLU/v27bV161ZJ0tatW1WrVi1XMJKkhIQE+fn5adu2bT6rFQAAXBm8unJ09OhRde3aVceOHVNOTo7+/Oc/KyQkRC+++KJycnI0e/ZsnxR35MgRvfnmmxozZoyeeuopbd++XQ8//LACAgI0dOhQpaamSpKio6PdxkVHR7u2paamKioqym179erVFR4e7upzvpycHOXk5LieZ2Rk+OR8AABAxefVlaNRo0apbdu2On36tIKDg13tffr00dq1a31WXEFBgW688UZNnjxZN9xwg0aMGKH777/fZ+HrQqZMmaKwsDDXo379+qV6PAAAUHF4FY6+/PJLjRs3TgEBAW7tDRo00G+//eaTwiSpbt26at68uVtbs2bNdOzYMUlSTEyMJMlms7n1sdlsrm0xMTFKS0tz256Xl6dTp065+pxv7Nixstvtrsfx48d9cj4AAKDi8yocFRQUKD8/v0j7r7/+qpCQkMsuqtCtt96qAwcOuLUdPHhQcXFxkv5YnB0TE+N2tSojI0Pbtm1TfHy8JCk+Pl5nzpzRjh07XH3WrVungoICtW/fvtjjBgYGKjQ01O0BAACqBq/CUefOnTV9+nTXc4vFoqysLD3zzDM+/UqRRx55RF9//bUmT56sw4cPa9GiRZozZ45GjhzpOu7o0aP13HPPadmyZdqzZ4+GDBmi2NhY9e7dW9IfV5q6du2q+++/X9988402b96spKQkDRgwgDvVAABAEV4tyH7llVfUpUsXNW/eXNnZ2br33nt16NAhRURE6IMPPvBZce3atdNnn32msWPHauLEiWrYsKGmT5+uQYMGufo88cQTOnv2rEaMGKEzZ86oQ4cOWrVqleszjiRp4cKFSkpKUqdOneTn56d+/fppxowZPqsTALyRm5tdZFlASVmtVoWFhfm4IgCSl+GoXr16+v777/Xhhx9q9+7dysrKUmJiogYNGuS2QNsX7r77bt19990X3G6xWDRx4kRNnDjxgn3Cw8P5wEcAFUpOToZ2796jyZMLZLVaPR4fEeGv8eOTCEhAKfAqHEl/3A4/ePBgX9YCAFWG03lO2dn+Cgrqozp1Gng01uE4qfT0JXI4HIQjoBR4FY4WLFhw0e1DhgzxqhgAqGqCgyMUElLX43HnzpVCMQAkeRmORo0a5fbc6XTK4XAoICBAVquVcAQAACotr+5WO336tNsjKytLBw4cUIcOHXy6IBsAAKCsef3daudr3LixXnjhhSJXlQAAACoTrxdkF7uz6tV14sQJX+4SqNLsdrscDofH42w2m3Jzc0uhIgC48nkVjpYtW+b23DAMpaSk6PXXX9ett97qk8KAqs5ut2vSpNeVnu70eKzDkam9e48oPDxbPvzQegCoErwKR4WfPl3IYrEoMjJSd911l1555RVf1AVUeQ6HQ+npTgUH95XVGunR2IKCfcrJmSmnM6+UqgOAK5dX4aigoMDXdQC4AKs10uNbvbOyvPvUZQCADxdkAwAAXAm8unI0ZsyYEvedNm2aN4cAAAAoF16Fo507d2rnzp1yOp1q0qSJJOngwYOqVq2abrzxRlc/i8XimyoBAADKiFfhqGfPngoJCdH8+fNVu3ZtSX98MOTw4cN122236dFHH/VpkQAAAGXFqzVHr7zyiqZMmeIKRpJUu3ZtPffcc9ytBgAAKjWvwlFGRoZOnjxZpP3kyZPKzMy87KIAAADKi1fhqE+fPho+fLiWLFmiX3/9Vb/++qs+/fRTJSYmqm/fvr6uEQAAoMx4teZo9uzZeuyxx3TvvffK6fzj03urV6+uxMREvfTSSz4tEAAAoCx5FY6sVqveeOMNvfTSS/rpp58kSY0aNVKNGjV8WhwAAEBZu6wPgUxJSVFKSooaN26sGjVqyDAMX9UFAABQLrwKR7///rs6deqka6+9Vt27d1dKSookKTExkdv4AQBApeZVOHrkkUfk7++vY8eOyWq1utr79++vVatW+aw4AACAsubVmqPVq1frv//9r+rVq+fW3rhxYx09etQnhQEAAJQHr64cnT171u2KUaFTp04pMDDwsosCAAAoL16Fo9tuu00LFixwPbdYLCooKNDUqVN15513+qw4AACAsubV22pTp05Vp06d9O233yo3N1dPPPGE9u7dq1OnTmnz5s2+rhEAAKDMeHXlqEWLFjp48KA6dOigXr166ezZs+rbt6927typRo0a+bpGAACAMuPxlSOn06muXbtq9uzZevrpp0ujJgAAgHLj8ZUjf39/7d69uzRqAQAAKHdeva02ePBgvfPOO76uBQAAoNx5tSA7Ly9P7777rtasWaM2bdoU+U61adOm+aQ4AACAsuZRODpy5IgaNGigH374QTfeeKMk6eDBg259LBaL76oDAAAoYx6Fo8aNGyslJUXr16+X9MfXhcyYMUPR0dGlUhwAAEBZ82jNkWEYbs9Xrlyps2fP+rQgAACA8uTVguxC54clAACAys6jcGSxWIqsKWKNEQAAuJJ4tObIMAwNGzbM9eWy2dnZ+sc//lHkbrUlS5b4rkIAAIAy5FE4Gjp0qNvzwYMH+7QYAACA8uZROJo7d25p1QEA8EBubrZsNpvX461Wq8LCwnxYEXDl8OpDIAEA5ScnJ0O7d+/R5MkFslqtXu0jIsJf48cnEZCAYhCOAKCScTrPKTvbX0FBfVSnTgOPxzscJ5WevkQOh4NwBBSDcAQAlVRwcIRCQup6NfbcOR8XA1xBLutzjgAAAK40hCMAAAATwhEAAIAJ4QgAAMCEcAQAAGBCOAIAADAhHAEAAJgQjgAAAEwIRwAAACaEIwAAABO+PgQoZXa7XQ6Hw+NxNptNubm5pVARAOBiCEdAKbLb7Zo06XWlpzs9HutwZGrv3iMKD89WSEgpFAcAKFalelvthRdekMVi0ejRo11t2dnZGjlypOrUqaOaNWuqX79+stlsbuOOHTumHj16yGq1KioqSo8//rjy8vLKuHpURQ6HQ+npTgUH91WdOg949AgK6q6cHENOJ69VAChLlebK0fbt2/XWW2+pVatWbu2PPPKIvvjiCy1evFhhYWFKSkpS3759tXnzZklSfn6+evTooZiYGG3ZskUpKSkaMmSI/P39NXny5PI4FVRBVmukx9+enpVlu3QnAIDPVYorR1lZWRo0aJDefvtt1a5d29Vut9v1zjvvaNq0abrrrrvUpk0bzZ07V1u2bNHXX38tSVq9erX27dun999/X61bt1a3bt00adIkzZo1i/UcAACgiEoRjkaOHKkePXooISHBrX3Hjh1yOp1u7U2bNtXVV1+trVu3SpK2bt2qli1bKjo62tWnS5cuysjI0N69e4s9Xk5OjjIyMtweAACgaqjwb6t9+OGH+u6777R9+/Yi21JTUxUQEKBatWq5tUdHRys1NdXVxxyMCrcXbivOlClT9O9//9sH1QMAgMqmQl85On78uEaNGqWFCxcqKCiozI47duxY2e121+P48eNldmwAAFC+KnQ42rFjh9LS0nTjjTeqevXqql69ujZu3KgZM2aoevXqio6OVm5urs6cOeM2zmazKSYmRpIUExNT5O61wueFfc4XGBio0NBQtwcAAKgaKnQ46tSpk/bs2aNdu3a5Hm3bttWgQYNcf/b399fatWtdYw4cOKBjx44pPj5ekhQfH689e/YoLS3N1Sc5OVmhoaFq3rx5mZ8TAACo2Cr0mqOQkBC1aNHCra1GjRqqU6eOqz0xMVFjxoxReHi4QkND9c9//lPx8fG6+eabJUmdO3dW8+bN9be//U1Tp05Vamqqxo0bp5EjRyowMLDMzwkAAFRsFToclcSrr74qPz8/9evXTzk5OerSpYveeOMN1/Zq1app+fLlevDBBxUfH68aNWpo6NChmjhxYjlWDQAAKqpKF442bNjg9jwoKEizZs3SrFmzLjgmLi5OK1asKOXKAADAlaBCrzkCAAAoa4QjAAAAE8IRAACACeEIAADAhHAEAABgQjgCAAAwIRwBAACYEI4AAABMCEcAAAAmhCMAAAATwhEAAIAJ4QgAAMCEcAQAAGBCOAIAADAhHAEAAJgQjgAAAEwIRwAAACaEIwAAABPCEQAAgAnhCAAAwIRwBAAAYEI4AgAAMCEcAQAAmBCOAAAATAhHAAAAJoQjAAAAE8IRAACASfXyLgAAUPZyc7Nls9m8Gmu1WhUWFubjioCKg3AEAFVMTk6Gdu/eo8mTC2S1Wj0eHxHhr/HjkwhIuGIRjgCginE6zyk7219BQX1Up04Dj8Y6HCeVnr5EDoeDcIQrFuEIAKqo4OAIhYTU9XjcuXOlUAxQgRCOgBKw2+1yOBwej7PZbMrNzS2FigAApYVwBFyC3W7XpEmvKz3d6fFYhyNTe/ceUXh4tkJCSqE4AIDPEY6AS3A4HEpPdyo4uK+s1kiPxhYU7FNOzkw5nXmlVB0AwNcIR0AJWa2RHq/PyMry7lZpAED54UMgAQAATAhHAAAAJoQjAAAAE8IRAACACeEIAADAhHAEAABgQjgCAAAwIRwBAACYEI4AAABMCEcAAAAmhCMAAAATwhEAAIAJ4QgAAMCEcAQAAGBCOAIAADAhHAEAAJgQjgAAAEwIRwAAACYVOhxNmTJF7dq1U0hIiKKiotS7d28dOHDArU92drZGjhypOnXqqGbNmurXr59sNptbn2PHjqlHjx6yWq2KiorS448/rry8vLI8FQAAUElU6HC0ceNGjRw5Ul9//bWSk5PldDrVuXNnnT171tXnkUce0X/+8x8tXrxYGzdu1IkTJ9S3b1/X9vz8fPXo0UO5ubnasmWL5s+fr3nz5mnChAnlcUoAAKCCq17eBVzMqlWr3J7PmzdPUVFR2rFjh26//XbZ7Xa98847WrRoke666y5J0ty5c9WsWTN9/fXXuvnmm7V69Wrt27dPa9asUXR0tFq3bq1JkybpX//6l5599lkFBASUx6kBAIAKqkJfOTqf3W6XJIWHh0uSduzYIafTqYSEBFefpk2b6uqrr9bWrVslSVu3blXLli0VHR3t6tOlSxdlZGRo7969xR4nJydHGRkZbg8AAFA1VJpwVFBQoNGjR+vWW29VixYtJEmpqakKCAhQrVq13PpGR0crNTXV1cccjAq3F24rzpQpUxQWFuZ61K9f38dnAwAAKqpKE45GjhypH374QR9++GGpH2vs2LGy2+2ux/Hjx0v9mAAAoGKo0GuOCiUlJWn58uXatGmT6tWr52qPiYlRbm6uzpw543b1yGazKSYmxtXnm2++cdtf4d1shX3OFxgYqMDAQB+fBQAAqAwq9JUjwzCUlJSkzz77TOvWrVPDhg3dtrdp00b+/v5au3atq+3AgQM6duyY4uPjJUnx8fHas2eP0tLSXH2Sk5MVGhqq5s2bl82JAACASqNCXzkaOXKkFi1apM8//1whISGuNUJhYWEKDg5WWFiYEhMTNWbMGIWHhys0NFT//Oc/FR8fr5tvvlmS1LlzZzVv3lx/+9vfNHXqVKWmpmrcuHEaOXIkV4cAwAu5udlFPk+upKxWq8LCwnxcEeBbFTocvfnmm5KkO+64w6197ty5GjZsmCTp1VdflZ+fn/r166ecnBx16dJFb7zxhqtvtWrVtHz5cj344IOKj49XjRo1NHToUE2cOLGsTgMArhg5ORnavXuPJk8ukNVq9Xh8RIS/xo9PIiChQqvQ4cgwjEv2CQoK0qxZszRr1qwL9omLi9OKFSt8WRoAVElO5zllZ/srKKiP6tRp4NFYh+Ok0tOXyOFwEI5QoVXocAQAqJiCgyMUElLX43HnzpVCMYCPEY5QZdjtdjkcDo/H2Ww25ebmlkJFAICKiHCEKsFut2vSpNeVnu70eKzDkam9e48oPDxbISGlUBwAoEIhHKFKcDgcSk93Kji4r6zWSI/GFhTsU07OTDmdeaVUHQCgIiEcoUqxWiM9XieRleXdLcsAgMqpQn8IJAAAQFkjHAEAAJgQjgAAAEwIRwAAACaEIwAAABPCEQAAgAnhCAAAwIRwBAAAYEI4AgAAMCEcAQAAmBCOAAAATAhHAAAAJoQjAAAAk+rlXQAAoOrIzc2WzWbzaqzValVYWJiPKwKKIhyhUrHb7XI4HB6Ps9lsys3NLYWKAJRUTk6Gdu/eo8mTC2S1Wj0eHxHhr/HjkwhIKHWEI1Qadrtdkya9rvR0p8djHY5M7d17ROHh2QoJKYXiAFyS03lO2dn+Cgrqozp1Gng01uE4qfT0JXI4HIQjlDrCESoNh8Oh9HSngoP7ymqN9GhsQcE+5eTMlNOZV0rVASip4OAIhYTU9XjcuXOlUAxQDMIRKh2rNdLjX6xZWd6tcQAAVD3crQYAAGBCOAIAADAhHAEAAJgQjgAAAEwIRwAAACaEIwAAABPCEQAAgAnhCAAAwIRwBAAAYEI4AgAAMCEcAQAAmBCOAAAATPjiWZQ5u90uh8Ph8Tibzabc3NxSqAgAgP8hHKFM2e12TZr0utLTnR6PdTgytXfvEYWHZyskpBSKAwBAhCOUMYfDofR0p4KD+8pqjfRobEHBPuXkzJTTmVdK1QEAQDhCObFaIxUSUtejMVlZtlKqBgCA/yEcAQAqhdzcbNls3v0nyWq1KiwszMcV4UpFOAIAVHg5ORnavXuPJk8ukNVq9Xh8RIS/xo9PIiChRAhHAIAKz+k8p+xsfwUF9VGdOg08GutwnFR6+hI5HA7CEUqEcAQAqDSCgyM8Xq8oSefOlUIxuGLxIZAAAAAmhCMAAAATwhEAAIAJa44AAFc8PgYAniAcwSt8PxqAyoKPAYCnCEfwGN+PBqAy4WMA4CnCETzG96MBqIz4GACUFOEIXuP70QAAVyLCEQAAF8Fi7qqnSoWjWbNm6aWXXlJqaqquv/56zZw5UzfddFN5lwUAqKBYzF01VZlw9NFHH2nMmDGaPXu22rdvr+nTp6tLly46cOCAoqKiyrs8r3l715gkOZ1O+fv7ezyOO84AVBUs5q6aqkw4mjZtmu6//34NHz5ckjR79mx98cUXevfdd/Xkk0+Wc3XeuZy7xnJzs3Xw4F5de21LBQQEeDSWO84AVDXeLua223lLrjKqEuEoNzdXO3bs0NixY11tfn5+SkhI0NatW8uxsj9czmcGnThxVmFhAzy+a+zkyX06c+ZHVa/e0+P/DXHHGQBc2uW+JRcSkq+kpMEKDQ31eGx5BavLeTejIoXBKhGO0tPTlZ+fr+joaLf26Oho/fjjj0X65+TkKCcnx/XcbrdLkjIyMnxem91u19Spc/T7754HjXPnMrV//y9q2/bPqlYtyKOxublnVVDgVG7uWeXkZHo11m4/Kn9/w6OxdvsxxjKWseU4tjyPXdXGpqcfkMMh5ea2VY0aMR6Nzcw8oW3b3tWvv2YoONjzYBUaWqD77/+rQry4vG8YhiwWi8fjMjMz9fbbi5WR4flYSapTp7qeeGKETwNS4b/bhuHh3xOjCvjtt98MScaWLVvc2h9//HHjpptuKtL/mWeeMSTx4MGDBw8ePK6Ax/Hjxz3KDVXiylFERISqVatW5H1fm82mmJiiaX7s2LEaM2aM63lBQYFOnTqlOnXqeJWmfSUjI0P169fX8ePHvbrMWpUwV55hvkqOuSo55sozzFfJlXSuDMNQZmamYmNjPdp/lQhHAQEBatOmjdauXavevXtL+iPwrF27VklJSUX6BwYGKjAw0K2tVq1aZVBpyYSGhvIXp4SYK88wXyXHXJUcc+UZ5qvkSjJX3rxNVyXCkSSNGTNGQ4cOVdu2bXXTTTdp+vTpOnv2rOvuNQAAAKkKhaP+/fvr5MmTmjBhglJTU9W6dWutWrWqyCJtAABQtVWZcCRJSUlJxb6NVlkEBgbqmWeeKfKWH4pirjzDfJUcc1VyzJVnmK+SK+25shiGp/e3AQAAXLn8yrsAAACAioRwBAAAYEI4AgAAMCEcAQAAmBCOytmmTZvUs2dPxcbGymKxaOnSpW7bhw0bJovF4vbo2rWrW59Tp05p0KBBCg0NVa1atZSYmKisrKwyPIuyc6n5kqT9+/frL3/5i8LCwlSjRg21a9dOx44dc23Pzs7WyJEjVadOHdWsWVP9+vXz+luzK7JLzdX5r6vCx0svveTqU1VeW5eaq6ysLCUlJalevXoKDg5W8+bNNXv2bLc+VeV1JV16vmw2m4YNG6bY2FhZrVZ17dpVhw4dcutTVeZrypQpateunUJCQhQVFaXevXvrwIEDbn1KMhfHjh1Tjx49ZLVaFRUVpccff1x5eVfWl3+XZK7mzJmjO+64Q6GhobJYLDpz5kyR/fji9xbhqJydPXtW119/vWbNmnXBPl27dlVKSorr8cEHH7htHzRokPbu3avk5GQtX75cmzZt0ogRI0q79HJxqfn66aef1KFDBzVt2lQbNmzQ7t27NX78eAUF/e+LeR955BH95z//0eLFi7Vx40adOHFCffv2LatTKDOXmivzayolJUXvvvuuLBaL+vXr5+pTVV5bl5qrMWPGaNWqVXr//fe1f/9+jR49WklJSVq2bJmrT1V5XUkXny/DMNS7d28dOXJEn3/+uXbu3Km4uDglJCTo7Nmzrn5VZb42btyokSNH6uuvv1ZycrKcTqc6d+7s0Vzk5+erR48eys3N1ZYtWzR//nzNmzdPEyZMKI9TKjUlmSuHw6GuXbvqqaeeuuB+fPJ7y+tvc4XPSTI+++wzt7ahQ4cavXr1uuCYffv2GZKM7du3u9pWrlxpWCwW47fffiulSiuG4uarf//+xuDBgy845syZM4a/v7+xePFiV9v+/fsNScbWrVtLq9RyV9xcna9Xr17GXXfd5XpeVV9bxc3VddddZ0ycONGt7cYbbzSefvppwzCq7uvKMIrO14EDBwxJxg8//OBqy8/PNyIjI423337bMIyqPV9paWmGJGPjxo2GYZRsLlasWGH4+fkZqamprj5vvvmmERoaauTk5JTtCZSh8+fKbP369YYk4/Tp027tvvq9xZWjSmDDhg2KiopSkyZN9OCDD+r33393bdu6datq1aqltm3butoSEhLk5+enbdu2lUe55aagoEBffPGFrr32WnXp0kVRUVFq37692yX/HTt2yOl0KiEhwdXWtGlTXX311dq6dWs5VF0x2Gw2ffHFF0pMTHS18dr6n1tuuUXLli3Tb7/9JsMwtH79eh08eFCdO3eWxOvKLCcnR5Lcrtb6+fkpMDBQX331laSqPV92u12SFB4eLqlkc7F161a1bNnS7RsdunTp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7t2768MPP7yM2QTgDcIRgArjp59+UteuXdWvXz/t3r1bH330kb766islJSUV2z8/P1+9e/eW1WrVtm3bNGfOHD399NPF9n366af12GOPadeuXbr22ms1cOBA5eXl6ZZbbtH06dMVGhqqlJQUpaSk6LHHHit2H1999ZWsVquaNWvmaisoKFC3bt20efNmvf/++9q3b59eeOEFVatWzdXH4XBoxowZ+vDDD7Vq1Spt2LBBffr00YoVK7RixQq99957euutt/TJJ5+4He+mm27Sl19+6ek0ArhM1cu7AABVw/Lly1WzZk23NvOVEkmaMmWKBg0apNGjR0uSGjdurBkzZqhjx4568803FRQU5NY/OTlZP/30kzZs2KCYmBhJ0vPPP68///nPRY7/2GOPqUePHpKkf//737ruuut0+PBhNW3aVGFhYbJYLK59XMjRo0cVHR3t9pbamjVr9M0332j//v269tprJUl/+tOf3MY5nU69+eabatSokSTpnnvu0XvvvSebzaaaNWuqefPmuvPOO7V+/Xr179/fNS42NlbHjx9XQUFBqb+NB+B/CEcAysSdd96pN998061t27ZtGjx4sOv5999/r927d2vhwoWuNsMwVFBQoJ9//tntio0kHThwQPXr13cLNTfddFOxx2/VqpXrz3Xr1pUkpaWlqWnTpiU+h3PnzhUJaLt27VK9evVcwag4VqvVFYwkKTo6Wg0aNHALi9HR0UpLS3MbFxwcrIKCAuXk5Cg4OLjEdQK4PIQjAGWiRo0auuaaa9zafv31V7fnWVlZeuCBB/Twww8XGX/11Vdf1vH9/f1df7ZYLJLk8Z1gEREROn36tFtbSUKL+diFxy+u7fx6Tp06pRo1ahCMgDJGOAJQYdx4443at29fkRB1IU2aNNHx48dls9kUHR0t6Y9b/T0VEBBQ5C2+4txwww1KTU3V6dOnVbt2bUl/XJH69ddfdfDgwYtePfLGDz/8oBtuuMGn+wRwabyJDaDC+Ne//qUtW7YoKSlJu3bt0qFDh/T5559fcEH2n//8ZzVq1EhDhw7V7t27tXnzZo0bN07S/64OlUSDBg2UlZWltWvXKj09XQ6Ho9h+N9xwgyIiIrR582ZXW8eOHXX77berX79+Sk5O1s8//6yVK1dq1apVHpx58b788kt17tz5svcDwDOEIwAVRqtWrbRx40YdPHhQt912m2644QZNmDBBsbGxxfavVq2ali5dqqysLLVr10733Xef626189cGXcwtt9yif/zjH+rfv78iIyM1derUCx5v+PDhbmuiJOnTTz9Vu3btNHDgQDVv3lxPPPFEia5EXcxvv/2mLVu2aPjw4Ze1HwCesxiGYZR3EQDgK5s3b1aHDh10+PBht0XQvpKamqrrrrtO3333neLi4ny+/0L/+te/dPr0ac2ZM6fUjgGgeKw5AlCpffbZZ6pZs6YaN26sw4cPa9SoUbr11ltLJRhJUkxMjN555x0dO3asVMNRVFSUxowZU2r7B3BhXDkCUKktWLBAzz33nI4dO6aIiAglJCTolVdeUZ06dcq7NACVFOEIAADAhAXZAAAAJoQjAAAAE8IRAACACeEIAADAhHAEAABgQjgCAAAwIRwBAACYEI4AAABMCEcAAAAm/x9al4o+0ohpZAAAAABJRU5ErkJggg==",
            "text/plain": [
              "<e2b_code_interpreter.models.Result at 0x7ab741ed5390>"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from e2b_code_interpreter import Sandbox\n",
        "\n",
        "with Sandbox(api_key=E2B_API_KEY) as code_interpreter:\n",
        "  code_results = chat_with_llama(\n",
        "    code_interpreter,\n",
        "    \"Visualize a distribution of height of men based on the latest data you know\"\n",
        "  )\n",
        "  if code_results:\n",
        "    first_result = code_results[0]\n",
        "  else:\n",
        "    print(\"No code results\")\n",
        "    exit(0)\n",
        "\n",
        "\n",
        "# This will render the image\n",
        "# You can also access the data directly\n",
        "# first_result.png\n",
        "# first_result.jpg\n",
        "# first_result.pdf\n",
        "# ...\n",
        "first_result"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
